//更酷的，十六进制实现十六进制编码和解码。 比标准0-F编码字符更多。
// 可自定义编码集

package hexf

import (
	"errors"
	"fmt"
)

// DefaultEncoding的行为就像golang/encoding/hex。
var DefaultEncoding = NewEncoding("0123456789abcdef")

// 使用特定编码字符表的编码。 例如："\x01\x02\x03\x04\x05\x06\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17"
type Encoding struct {
	hextable string
}

// NewEncoding使用给定的hextable构造一个Encoding。
func NewEncoding(hextable string) *Encoding {
	return &Encoding{hextable}
}

// EncodedLen返回n个源字节的编码长度。
func EncodedLen(n int) int { return n * 2 }

//编码将src编码为EncodedLen（len（src））
// dst的字节。 为方便起见，它返回数字
//写入dst的字节数，但此值始终为EncodedLen（len（src））。
//编码实现十六进制编码。
func (e *Encoding) Encode(dst, src []byte) int {
	for i, v := range src {
		fmt.Println(`i=`,i,`,v=`,v)
		dst[i*2] = e.hextable[v>>4]
		dst[i*2+1] = e.hextable[v&0x0f]
	}

	return len(src) * 2
}

// ErrLength来自对奇数长度切片的解码。
var ErrLength = errors.New("encoding/hex: odd length hex string")

// InvalidByteError值描述了十六进制字符串中无效字节导致的错误。
type InvalidByteError byte

func (e InvalidByteError) Error() string {
	return fmt.Sprintf("encoding/hex: invalid byte: %#U", rune(e))
}

func DecodedLen(x int) int { return x / 2 }

//解码将src解码为DecodedLen（len（src））字节，返回实际值
//写入dst的字节数。
//如果Decode遇到无效的输入，它将返回描述失败的错误。
func (e *Encoding) Decode(dst, src []byte) (int, error) {
	if len(src)%2 == 1 {
		return 0, ErrLength
	}

	for i := 0; i < len(src)/2; i++ {
		a, ok := e.fromHexChar(src[i*2])
		if !ok {
			return 0, InvalidByteError(src[i*2])
		}
		b, ok := e.fromHexChar(src[i*2+1])
		if !ok {
			return 0, InvalidByteError(src[i*2+1])
		}
		dst[i] = (a << 4) | b
	}

	return len(src) / 2, nil
}

// fromHexChar将十六进制字符转换为其值和成功标志。
func (e *Encoding) fromHexChar(c byte) (byte, bool) {
	for i, ch := range []byte(e.hextable) {
		if ch == c {
			return byte(i), true
		}
	}

	return 0, false
}

// EncodeToString返回src的十六进制编码。
func (e *Encoding) EncodeToString(src []byte) string {
	dst := make([]byte, EncodedLen(len(src)))
	fmt.Println(`dst1=`,dst)
	i:=e.Encode(dst, src)
	fmt.Println(`i=`,i)
	fmt.Println(`dst2=`,dst)
	return string(dst)
}

// DecodeString返回由十六进制字符串s表示的字节。
func (e *Encoding) DecodeString(s string) ([]byte, error) {
	src := []byte(s)
	dst := make([]byte, DecodedLen(len(src)))
	_, err := e.Decode(dst, src)
	if err != nil {
		return nil, err
	}
	return dst, nil
}
